import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;

public class Face {

	private int id;
	
	private ArrayList<Imagem> faces;
	
	private ArrayList<Imagem> facesTreino;
	
	private ArrayList<Imagem> facesTeste;
	
	private MLP rede;
	
	double[][] faceMedia;
	
	boolean media;

	public Face(int id, boolean media) {
		super();
		this.id = id;
		faces = new ArrayList<Imagem>();
		facesTreino = new ArrayList<Imagem>();
		this.media = media;
	}

	public void separaFaces(int qtdElementosTreino) {
		Collections.shuffle(faces);
		facesTreino = new ArrayList<Imagem>();
		for (int i = 0; i < qtdElementosTreino; i++) {
			facesTreino.add(faces.get(i));
		}
		facesTeste = new ArrayList<Imagem>();
		for (int i = qtdElementosTreino; i < faces.size(); i++) {
			facesTeste.add(faces.get(i));
		}
	}
	
	public boolean contemLista(ArrayList<Imagem> imagensTeste, String id) {
		for (Imagem imagem : imagensTeste) {
			if(imagem.getIdentificador().equals(id)) {
				return true;
			}
		}
		return false;
	}
	
	public void separaFaces(ArrayList<Imagem> imagensTeste) {
		facesTreino = new ArrayList<Imagem>();
		facesTeste = new ArrayList<Imagem>();
		for (int i = 0; i < faces.size(); i++) {
			if(contemLista(imagensTeste, faces.get(i).getIdentificador())) {
				facesTeste.add(faces.get(i));
			} else {
				facesTreino.add(faces.get(i));
			}
		}
	}
	
	public void separaFaces() {
		//Collections.shuffle(faces);
		facesTreino = faces;
	}
	
	public void separaFaces(int qtdElementosTreino, int numElementos) {
		//Collections.shuffle(faces);
		facesTreino = new ArrayList<Imagem>();
		for (int i = 0; i < qtdElementosTreino; i++) {
			facesTreino.add(faces.get(i));
		}
		facesTeste = new ArrayList<Imagem>();
		for (int i = qtdElementosTreino; i < faces.size() && i < numElementos; i++) {
			facesTeste.add(faces.get(i));
		}
		faces = new ArrayList<Imagem>();
	}
	
	private double distanciaTreinoMedia = 0;
	
	public double getDistanciaTreinoMedia() {
		return distanciaTreinoMedia;
	}

	public void setDistanciaTreinoMedia(double distanciaTreinoMedia) {
		this.distanciaTreinoMedia = distanciaTreinoMedia;
	}

	public void treina(int tamanhoEntrada,
			int epocas, boolean rprop, double taxaAprendizagem, double fatorTaxaAprendizagem, int[] camadas) throws Exception {
		rede = new MLP(tamanhoEntrada, camadas);
		//rede.batch = false;
		rede.treinaAutoassociativaImagem(taxaAprendizagem, fatorTaxaAprendizagem, epocas, facesTreino);
	}
	
	public void treinaExclui(int tamanhoEntrada,
			int epocas, boolean rprop, double taxaAprendizagem, double fatorTaxaAprendizagem, int[] camadas, Imagem exclui) throws Exception {
		//System.out.println("Treino face: "+id);
		rede = new MLP(tamanhoEntrada, camadas);
		ArrayList<Imagem> treino = new ArrayList<Imagem>();
		for (Imagem imagem : facesTreino) {
			if(!imagem.getIdentificador().equals(exclui)) {
				treino.add(imagem);
			}
		}
		//rede.batch = false;
		rede.treinaAutoassociativaImagem(taxaAprendizagem, fatorTaxaAprendizagem, epocas, treino);
	}
	
	public double distancia(double[][] imagemTmp) throws Exception {
		double[][] imagem = null;
		if(media) {
			imagem = UtilImage.subtracao(imagemTmp, faceMedia);
		} else {
			imagem = imagemTmp;
		}
		double[] imagemArray = UtilImage.converteMatrizToArray(imagem);
		return UtilImage.distancia2(imagemArray, rede.calculaSaidaRede(imagemArray));
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Face other = (Face) obj;
		if (id != other.id)
			return false;
		return true;
	}
	
	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public ArrayList<Imagem> getFaces() {
		return faces;
	}

	public void setFaces(ArrayList<Imagem> faces) {
		this.faces = faces;
	}

	public ArrayList<Imagem> getFacesTreino() {
		return facesTreino;
	}

	public void setFacesTreino(ArrayList<Imagem> facesTreino) {
		this.facesTreino = facesTreino;
	}

	public ArrayList<Imagem> getFacesTeste() {
		return facesTeste;
	}

	public void setFacesTeste(ArrayList<Imagem> facesTeste) {
		this.facesTeste = facesTeste;
	}
	
}
